<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>OpenMesh: Using Smart Handles</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="logo_align.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="rwth_vci_rgb.jpg"/></td>
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">OpenMesh
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('a04347.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Using Smart Handles </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>This examples shows:</p>
<ul>
<li>How to use Smart Handles and ranges to navigate on the mesh</li>
<li>How to use Smart Ranges</li>
</ul>
<p>So far we have used methods such as halfedge_handle(), next_halfedge_handle(), prev_halfedge_handle(), oppopsite_halfedge_handle(), face_handle(), to_vertex_handle(), and some others, to navigate on that mesh. These functions are defined on a mesh and require as input a handle to an element of the mesh, such as VertexHandle or HalfedgeHandle. In the following example we iterate over all vertices of a triangle mesh and for each vertex we create a list of the vertices that lie opposite of the edges in the ring around the vertex:</p>
<div class="fragment"><div class="line"><span class="comment">// iterate over vertices of the mesh</span></div><div class="line"><span class="keywordflow">for</span> (<span class="keyword">auto</span> vh : mesh.vertices())</div><div class="line">{</div><div class="line">  std::vector&lt;OpenMesh::VertexHandle&gt; opposite_vertices;</div><div class="line">  <span class="comment">// iterate over all outgoing halfedges</span></div><div class="line">  <span class="keywordflow">for</span> (<span class="keyword">auto</span> heh : mesh.voh_range(vh))</div><div class="line">  {</div><div class="line">    <span class="comment">// navigate to the opposite vertex and store it in the vector</span></div><div class="line">    opposite_vertices.push_back(mesh.to_vertex_handle(mesh.next_halfedge_handle(mesh.opposite_halfedge_handle(mesh.next_halfedge_handle(heh)))));</div><div class="line">  }</div><div class="line">}</div></div><!-- fragment --><p>For a more concise way of navigating <a class="el" href="a01233.html" title="Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...">OpenMesh</a> provides smart handles, <a class="el" href="a02405.html" title="Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...">OpenMesh::SmartVertexHandle</a>, <a class="el" href="a02409.html">OpenMesh::SmartHalfedgeHandle</a>, <a class="el" href="a02413.html">OpenMesh::SmartEdgeHandle</a>, and <a class="el" href="a02417.html">OpenMesh::SmartFaceHandle</a>. Smart handles are smart, because they know to which mesh they belong. This allows them to provide functions for navigating the mesh allowing us to write the above code much simpler:</p>
<div class="fragment"><div class="line"><span class="comment">// iterate over vertices of the mesh</span></div><div class="line"><span class="keywordflow">for</span> (<span class="keyword">auto</span> vh : mesh.vertices())</div><div class="line">{</div><div class="line">  <span class="comment">// iterate over all outgoing halfedges</span></div><div class="line">  std::vector&lt;OpenMesh::VertexHandle&gt; opposite_vertices;</div><div class="line">  <span class="keywordflow">for</span> (<span class="keyword">auto</span> heh : vh.outgoing_halfedges())</div><div class="line">  {</div><div class="line">    <span class="comment">// navigate to the opposite vertex and store it in the vector</span></div><div class="line">    opposite_vertices.push_back(heh.next().opp().next().to());</div><div class="line">  }</div><div class="line">}</div></div><!-- fragment --><p>The ranges of <a class="el" href="a01233.html" title="Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...">OpenMesh</a> that are returned by functions like voh_range() or outgoing_halfedges() all provide a few methods than can simplify some calculations (see <a class="el" href="a02449.html" title="Base class for all smart range types. ">OpenMesh::SmartRangeT</a>). One example is the to_vector() method which convertes the range of elements into a vector containing the elements. All of these methods take a functor as argument (sometimes optional) which is called for each element of the range. With this, the above code can also be implemented like this:</p>
<div class="fragment"><div class="line"><span class="comment">// iterate over vertices of the mesh</span></div><div class="line"><span class="keywordflow">for</span> (<span class="keyword">auto</span> vh : mesh.vertices())</div><div class="line">{</div><div class="line">  <span class="comment">// create lambda that returns opposite vertex</span></div><div class="line">  <span class="keyword">auto</span> opposite_vertex = [](<a class="code" href="a02409.html">OpenMesh::SmartHalfedgeHandle</a> heh) { <span class="keywordflow">return</span> heh.next().opp().next().to(); };</div><div class="line">  <span class="comment">// create vector containing all opposite vertices</span></div><div class="line">  <span class="keyword">auto</span> opposite_vertices = vh.outgoing_halfedges().to_vector(opposite_vertex);</div><div class="line">}</div></div><!-- fragment --> <hr/>
<h2>Code Example</h2>
<p>In this example, we will use bi-laplacian smoothing on a mesh. We store the <code>laplace</code> vector which is the vector pointing from a vertex to the center of gravity of its neighboring vertices in a vertex property.</p>
 <div class="fragment"><div class="line">    <span class="comment">// Add a vertex property storing the laplace vector</span></div><div class="line">    <span class="keyword">auto</span> laplace = <a class="code" href="a02597.html">OpenMesh::VProp&lt;MyMesh::Point&gt;</a>(mesh);</div></div><!-- fragment --></p>
<p>To compute the center of gravity, i.e. the average position, we use the avg() method of the range of 1-ring vertices and pass in a PropertyManager acting as functor returning the corresponding point of a vertex.</p>
<p><div class="fragment"><div class="line">    <span class="comment">// Get a propertymanager of the points property of the mesh to use as functor</span></div><div class="line">    <span class="keyword">auto</span> points = OpenMesh::getPointsProperty(mesh);</div><div class="line">    </div><div class="line">    <span class="comment">// Smooth the mesh several times</span></div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; iterations; ++i) {</div><div class="line">      <span class="comment">// Iterate over all vertices to compute laplace vector</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices())</div><div class="line">        laplace(vh) = vh.vertices().avg(points) - points(vh);</div></div><!-- fragment --></p>
<p>Similarily we compute the update vector as the laplace of the freshly computed laplace vectors by simply exchanging the points property manager with the laplace property manager.</p>
<p><div class="fragment"><div class="line">      <span class="comment">// Iterate over all vertices to compute the laplace vector of the laplace vectors</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices())</div><div class="line">        bi_laplace(vh) =  (vh.vertices().avg(laplace) - laplace(vh));</div></div><!-- fragment --></p>
<p>Finally, we apply the update after damping it by a factor of -0.5.</p>
<p><div class="fragment"></div><!-- fragment --></p>
<p>Below is the complete source code:</p>
<div class="fragment"><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/IO/MeshIO.hh&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/Mesh/DefaultTriMesh.hh&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;OpenMesh/Core/Utils/PropertyManager.hh&gt;</span></div><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><span class="preprocessor">#include &lt;vector&gt;</span></div><div class="line"></div><div class="line"><span class="keyword">using</span> MyMesh = <a class="code" href="a02377.html">OpenMesh::TriMesh</a>;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>** argv)</div><div class="line">{</div><div class="line">  <span class="comment">// Read command line options</span></div><div class="line">  MyMesh mesh;</div><div class="line">  <span class="keywordflow">if</span> (argc != 4) {</div><div class="line">    std::cerr &lt;&lt; <span class="stringliteral">&quot;Usage: &quot;</span> &lt;&lt; argv[0] &lt;&lt; <span class="stringliteral">&quot; #iterations infile outfile&quot;</span> &lt;&lt; std::endl;</div><div class="line">    <span class="keywordflow">return</span> 1;</div><div class="line">  }</div><div class="line">  <span class="keyword">const</span> <span class="keywordtype">int</span> iterations = argv[1];</div><div class="line">  <span class="keyword">const</span> std::string infile = argv[2];</div><div class="line">  <span class="keyword">const</span> std::string outfile = argv[3];</div><div class="line">  </div><div class="line">  <span class="comment">// Read mesh file</span></div><div class="line">  <span class="keywordflow">if</span> (!<a class="code" href="a01236.html#ac417960ec28ffdd7e7003a2b1ebb2d1c">OpenMesh::IO::read_mesh</a>(mesh, infile)) {</div><div class="line">    std::cerr &lt;&lt; <span class="stringliteral">&quot;Error: Cannot read mesh from &quot;</span> &lt;&lt; infile &lt;&lt; std::endl;</div><div class="line">    <span class="keywordflow">return</span> 1;</div><div class="line">  }</div><div class="line">  </div><div class="line">  {</div><div class="line">    <span class="comment">// Add a vertex property storing the laplace vector</span></div><div class="line">    <span class="keyword">auto</span> laplace = <a class="code" href="a02597.html">OpenMesh::VProp&lt;MyMesh::Point&gt;</a>(mesh);</div><div class="line">    </div><div class="line">    <span class="comment">// Add a vertex property storing the laplace of the laplace</span></div><div class="line">    <span class="keyword">auto</span> bi_laplace = <a class="code" href="a02597.html">OpenMesh::VProp&lt;MyMesh::Point&gt;</a>(mesh);</div><div class="line">    </div><div class="line">    <span class="comment">// Get a propertymanager of the points property of the mesh to use as functor</span></div><div class="line">    <span class="keyword">auto</span> points = OpenMesh::getPointsProperty(mesh);</div><div class="line">    </div><div class="line">    <span class="comment">// Smooth the mesh several times</span></div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; iterations; ++i) {</div><div class="line">      <span class="comment">// Iterate over all vertices to compute laplace vector</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices())</div><div class="line">        laplace(vh) = vh.vertices().avg(points) - points(vh);</div><div class="line">      </div><div class="line">      <span class="comment">// Iterate over all vertices to compute the laplace vector of the laplace vectors</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices())</div><div class="line">        bi_laplace(vh) =  (vh.vertices().avg(laplace) - laplace(vh));</div><div class="line">      </div><div class="line">      <span class="comment">// update points by substracting the bi-laplacian damped by a factor of 0.5</span></div><div class="line">      <span class="keywordflow">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>&amp; vh : mesh.vertices())</div><div class="line">        points(vh) += -0.5 * bi_laplace(vh);</div><div class="line">    }</div><div class="line">  } <span class="comment">// The laplace and update properties are removed from the mesh at the end of this scope.</span></div><div class="line">  </div><div class="line">  </div><div class="line">  <span class="comment">// Write mesh file</span></div><div class="line">  <span class="keywordflow">if</span> (!<a class="code" href="a01236.html#ac417960ec28ffdd7e7003a2b1ebb2d1c">OpenMesh::IO::read_mesh</a>(mesh, outfile)) {</div><div class="line">    std::cerr &lt;&lt; <span class="stringliteral">&quot;Error: Cannot write mesh to &quot;</span> &lt;&lt; outfile &lt;&lt; std::endl;</div><div class="line">    <span class="keywordflow">return</span> 1;</div><div class="line">  }</div><div class="line">}</div><div class="line"></div></div><!-- fragment --> <hr/>
 </div></div><!-- contents -->
</div><!-- doc-content -->
<hr>
<address>
<small>
<a href="http://www.rwth-graphics.de" style="text-decoration:none;">
</a>
Project <b>OpenMesh</b>, 
&copy;&nbsp; Computer Graphics Group, RWTH Aachen.
Documentation generated using 
<a class="el" href="http://www.doxygen.org/index.html">
<b>doxygen</b>
</a>.
</small>
</address>
</body>
</html>
